import {
  useCallback,
  useEffect,
  useMemo,
  useState,
} from 'react'
import useSWR, { useSWRConfig } from 'swr'
import { useContext } from 'use-context-selector'
import type {
  CustomConfigurationModelFixedFields,
  DefaultModel,
  DefaultModelResponse,
  Model,
  ModelTypeEnum,
} from './declarations'
import {
  ConfigurationMethodEnum,
  ModelStatusEnum,
} from './declarations'
import I18n from '@/context/i18n'
import {
  fetchModelProviders,
  getPayUrl,
} from '@/services/common'
import { useProviderContext } from '@/context/provider-context'
import { modelFetchModelProviderCredentials } from '@/services/local'
import { modelGetProviderAndModelsByType, modelFetchDefaultModal } from '@/services/local';

type UseDefaultModelAndModelList = (
  defaultModel: DefaultModelResponse | undefined,
  modelList: Model[],
) => [DefaultModel | undefined, (model: DefaultModel) => void]

export const useSystemDefaultModelAndModelList: UseDefaultModelAndModelList = (
  defaultModel,
  modelList,
) => {
  const [defaultModelState, setDefaultModelState] = useState<DefaultModel | undefined>({
    provider: defaultModel?.provider.provider,
    model: defaultModel?.model,
  });

  useEffect(() => {
    if (defaultModel && defaultModel != defaultModelState) {
      if (defaultModelState && (defaultModel?.provider.provider != defaultModelState.provider || defaultModel.model != defaultModelState.model)) {
        setDefaultModelState({
          provider: defaultModel?.provider.provider,
          model: defaultModel?.model,
        });
      }
    }
  }, [defaultModel]);

  const handleDefaultModelChange = useCallback((model: DefaultModel) => {
    setDefaultModelState(model)
  }, []);

  return [defaultModelState, handleDefaultModelChange]
}

export const useLanguage = () => {
  const { locale } = useContext(I18n)
  return locale.replace('-', '_')
}

export const useProviderCredentialsAndLoadBalancing = (
  provider: string,
  configurationMethod: ConfigurationMethodEnum,
  configured?: boolean,
  currentCustomConfigurationModelFixedFields?: CustomConfigurationModelFixedFields,
) => {
  const { data: predefinedFormSchemasValue, mutate: mutatePredefined } = useSWR(provider, modelFetchModelProviderCredentials,)
  const { data: customFormSchemasValue, mutate: mutateCustomized } = useSWR(provider, modelFetchModelProviderCredentials,)

  const credentials = useMemo(() => {
    return configurationMethod === ConfigurationMethodEnum.predefinedModel
      ? predefinedFormSchemasValue?.credentials
      : customFormSchemasValue?.credentials
        ? {
          ...customFormSchemasValue?.credentials,
          ...currentCustomConfigurationModelFixedFields,
        }
        : undefined
  }, [
    configurationMethod,
    currentCustomConfigurationModelFixedFields,
    customFormSchemasValue?.credentials,
    predefinedFormSchemasValue?.credentials,
  ])

  const mutate = useMemo(() => () => {
    mutatePredefined()
    mutateCustomized()
  }, [mutateCustomized, mutatePredefined])

  return {
    credentials,
    loadBalancing: (configurationMethod === ConfigurationMethodEnum.predefinedModel
      ? predefinedFormSchemasValue
      : customFormSchemasValue
    )?.load_balancing,
    mutate,
  }
  // as ([Record<string, string | boolean | undefined> | undefined, ModelLoadBalancingConfig | undefined])
}

export const useModelList = (type: ModelTypeEnum) => {
  const [modelList, setModelList] = useState<any[]>([]);
  useEffect(() => {
    modelGetProviderAndModelsByType(type).then((res) => {
      if (res) {
        setModelList(res);
      }
    });
  }, [type]);

  return {
    data: modelList,
  }
}

export const useDefaultModel = (type: ModelTypeEnum) => {
  const [mode, setModel] = useState<any>();

  useEffect(() => {
    modelFetchDefaultModal(type).then((res) => {
      if (res) {
        setModel(res);
      }
    });
  }, [type]);

  return {
    data: mode,
  }
}

export const useCurrentProviderAndModel = (modelList: Model[], defaultModel?: DefaultModel) => {
  const currentProvider = modelList.find(provider => provider.provider === defaultModel?.provider)
  const currentModel = currentProvider?.models.find(model => model.model === defaultModel?.model)

  return {
    currentProvider,
    currentModel,
  }
}

export const useTextGenerationCurrentProviderAndModelAndModelList = (defaultModel?: DefaultModel) => {
  const { textGenerationModelList, } = useProviderContext()
  const activeTextGenerationModelList = textGenerationModelList.filter(model => model.status === ModelStatusEnum.active)
  const {
    currentProvider,
    currentModel,
  } = useCurrentProviderAndModel(textGenerationModelList, defaultModel)

  return {
    currentProvider,
    currentModel,
    textGenerationModelList,
    activeTextGenerationModelList,
  }
}

export const useTTSCurrentProviderAndModelAndModelList = (defaultModel?: DefaultModel) => {
  const { ttsModelList } = useProviderContext()
  const activeTTSModelList = ttsModelList.filter(model => model.status === ModelStatusEnum.active)
  const {
    currentProvider,
    currentModel,
  } = useCurrentProviderAndModel(ttsModelList, defaultModel)

  return {
    currentProvider,
    currentModel,
    ttsModelList,
    activeTTSModelList,
  }
}

export const useTextEmbeddingCurrentProviderAndModelAndModelList = (defaultModel?: DefaultModel) => {
  const { textEmbeddingModelList } = useProviderContext()
  const activeTextEmbeddingModelList = textEmbeddingModelList.filter(model => model.status === ModelStatusEnum.active)
  const {
    currentProvider,
    currentModel,
  } = useCurrentProviderAndModel(textEmbeddingModelList, defaultModel)

  return {
    currentProvider,
    currentModel,
    textEmbeddingModelList,
    activeTextEmbeddingModelList,
  }
}


export const useSpeech2textCurrentProviderAndModelAndModelList = (defaultModel?: DefaultModel) => {
  const { speech2textModelList } = useProviderContext()
  const activeSpeech2textModelList = speech2textModelList.filter(model => model.status === ModelStatusEnum.active)
  const {
    currentProvider,
    currentModel,
  } = useCurrentProviderAndModel(speech2textModelList, defaultModel)

  return {
    currentProvider,
    currentModel,
    speech2textModelList,
    activeSpeech2textModelList,
  }
}

export const useModelListAndDefaultModel = (type: ModelTypeEnum) => {
  const { data: modelList } = useModelList(type)
  const { data: defaultModel } = useDefaultModel(type)

  return {
    modelList,
    defaultModel,
  }
}

export const useModelListAndDefaultModelAndCurrentProviderAndModel = (type: ModelTypeEnum) => {
  const { modelList, defaultModel } = useModelListAndDefaultModel(type)
  const { currentProvider, currentModel } = useCurrentProviderAndModel(
    modelList,
    { provider: defaultModel?.provider.provider || '', model: defaultModel?.model || '' },
  )

  return {
    modelList,
    defaultModel,
    currentProvider,
    currentModel,
  }
}

export const useUpdateModelList = () => {
  const { mutate } = useSWRConfig()

  const updateModelList = useCallback((type: ModelTypeEnum) => {
    mutate(`/workspaces/current/models/model-types/${type}`)
  }, [mutate])

  return updateModelList
}

export const useAnthropicBuyQuota = () => {
  const [loading, setLoading] = useState(false)

  const handleGetPayUrl = async () => {
    if (loading)
      return

    setLoading(true)
    try {
      const res = await getPayUrl('/workspaces/current/model-providers/anthropic/checkout-url')

      window.location.href = res.url
    }
    finally {
      setLoading(false)
    }
  }

  return handleGetPayUrl
}

export const useModelProviders = () => {
  const { data: providersData, mutate, isLoading } = useSWR('/workspaces/current/model-providers', fetchModelProviders)

  return {
    data: providersData?.data || [],
    mutate,
    isLoading,
  }
}

export const useUpdateModelProviders = () => {
  const { mutate } = useSWRConfig()

  const updateModelProviders = useCallback(() => {
    mutate('/workspaces/current/model-providers')
  }, [mutate])

  return updateModelProviders
}
